package com.lonely.purchase.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Tuple;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lonely.common.utils.JsonUtil;
import com.lonely.common.utils.SecurityUtils;
import com.lonely.purchase.domain.dto.materialpurchase.DeductionReplenishDTO;
import com.lonely.purchase.domain.entity.SysMaterialPurchase;
import com.lonely.purchase.domain.entity.SysMaterialPurchaseDeductionReplenish;
import com.lonely.purchase.enums.MaterialPurchaseEnum;
import com.lonely.purchase.mapper.SysMaterialPurchaseDeductionReplenishMapper;
import com.lonely.purchase.service.IMaterialPurchaseDeductionReplenishService;
import com.lonely.purchase.service.IMaterialPurchaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author : 黄志标
 * @date: 2025/7/23 15:20
 * @description: 物料采购扣减补货服务实现类
 */
@Service
public class MaterialPurchaseDeductionReplenishServiceImpl extends ServiceImpl<SysMaterialPurchaseDeductionReplenishMapper, SysMaterialPurchaseDeductionReplenish> implements IMaterialPurchaseDeductionReplenishService {

    @Autowired
    private IMaterialPurchaseService materialPurchaseService;

    /**
     * 扣减补料
     *
     * @param deductionReplenishDTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addDeductionReplenish(DeductionReplenishDTO deductionReplenishDTO) {
        SysMaterialPurchase materialPurchase = this.materialPurchaseService.getById(deductionReplenishDTO.getId());
        Assert.notNull(materialPurchase, "物料采购信息不存在");

        SysMaterialPurchaseDeductionReplenish purchaseDeductionReplenish = new SysMaterialPurchaseDeductionReplenish();
        purchaseDeductionReplenish.setMaterialPurchaseId(deductionReplenishDTO.getId());
        purchaseDeductionReplenish.setFailType(deductionReplenishDTO.getFailType());
        purchaseDeductionReplenish.setAttachments(JsonUtil.toJsonString(deductionReplenishDTO.getAttachments()));
        purchaseDeductionReplenish.setCreateBy(SecurityUtils.getUserId());
        purchaseDeductionReplenish.setUpdateBy(SecurityUtils.getUserId());
        purchaseDeductionReplenish.setRemark(deductionReplenishDTO.getFailRemark());


        MaterialPurchaseEnum.MaterialPurchaseFailTypeEnum purchaseFailTypeEnum = MaterialPurchaseEnum.MaterialPurchaseFailTypeEnum.getByFailType(deductionReplenishDTO.getFailType());
        switch (purchaseFailTypeEnum) {
            case deduction:
                Assert.notEmpty(deductionReplenishDTO.getDeductionQuantity(), "扣减数量不能为空");
                Assert.isTrue(NumberUtil.isLessOrEqual(NumberUtil.toBigDecimal(deductionReplenishDTO.getDeductionQuantity()),
                        NumberUtil.toBigDecimal(materialPurchase.getRecycledMaterialsVolume())), "扣减数量不能大于回收量");
                purchaseDeductionReplenish.setDeductionQuantity(deductionReplenishDTO.getDeductionQuantity());

                // 扣减回收量
                materialPurchase.setRecycledMaterialsVolume(NumberUtil.sub(materialPurchase.getRecycledMaterialsVolume(), deductionReplenishDTO.getDeductionQuantity()).stripTrailingZeros().toPlainString());
                break;
            case replenish:
                Assert.notEmpty(deductionReplenishDTO.getReplenishQuantity(), "补料数量不能为空");
                purchaseDeductionReplenish.setReplenishQuantity(deductionReplenishDTO.getReplenishQuantity());

                // 补充回收量
                materialPurchase.setRecycledMaterialsVolume(NumberUtil.add(materialPurchase.getRecycledMaterialsVolume(), deductionReplenishDTO.getReplenishQuantity()).stripTrailingZeros().toPlainString());
                break;
        }

        super.save(purchaseDeductionReplenish);
        this.materialPurchaseService.updateById(materialPurchase);

    }

    /**
     * 获取指定物料采购对应的扣损总数量和补料总数量
     *
     * @param materialPurchaseIds
     * @return
     */
    @Override
    public Map<Long, Tuple> getMaterialPurchaseDeductionReplenishQuantityMap(List<Long> materialPurchaseIds) {
        if (CollUtil.isEmpty(materialPurchaseIds)) {
            return new HashMap<>();
        }

        Map<Long, Tuple> result = new HashMap<>();

        List<SysMaterialPurchaseDeductionReplenish> deductionReplenishes = super.list(new LambdaQueryWrapper<SysMaterialPurchaseDeductionReplenish>()
                .in(SysMaterialPurchaseDeductionReplenish::getMaterialPurchaseId, materialPurchaseIds)
        );

        Map<Long, List<SysMaterialPurchaseDeductionReplenish>> dedectionReplenishMap = deductionReplenishes.stream().collect(Collectors.groupingBy(SysMaterialPurchaseDeductionReplenish::getMaterialPurchaseId));
        dedectionReplenishMap.forEach((materialPurchaseId, deductionReplenishList) -> {

            // 计算扣损的总数量
            BigDecimal deductionQuantity = deductionReplenishList.stream()
                    .filter(deductionReplenish -> Objects.equals(deductionReplenish.getFailType(), MaterialPurchaseEnum.MaterialPurchaseFailTypeEnum.deduction.getFailType()))
                    .map(SysMaterialPurchaseDeductionReplenish::getDeductionQuantity).map(BigDecimal::new).reduce(BigDecimal.ZERO, BigDecimal::add);
            String totalDeductionQuantity = NumberUtil.round(deductionQuantity, 2).stripTrailingZeros().toPlainString();

            // 计算补料的总数量
            BigDecimal replenishQuantity = deductionReplenishList.stream()
                    .filter(deductionReplenish -> Objects.equals(deductionReplenish.getFailType(), MaterialPurchaseEnum.MaterialPurchaseFailTypeEnum.replenish.getFailType()))
                    .map(SysMaterialPurchaseDeductionReplenish::getReplenishQuantity).map(BigDecimal::new).reduce(BigDecimal.ZERO, BigDecimal::add);
            String totalReplenishQuantity = NumberUtil.round(replenishQuantity, 2).stripTrailingZeros().toPlainString();

            result.put(materialPurchaseId, new Tuple(totalDeductionQuantity, totalReplenishQuantity));
        });

        return result;
    }
}
